/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package servidor;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author javi
 */
public class ControladorClientes implements Runnable {

    public static final String PREFIX_COOKIE = "Cookie:";
    public static final String PREFIX_GET = "GET";
    public static final String PREFIX_POST = "POST";
    private ImpresorPost impresor;
    private Socket unCliente;
    private BufferedReader input;
    private DataOutputStream output;
    private byte[] bytesContenido;
    private HashSet<String> sesiones;
    private String cabecera, tipoPeticion, cookie;
    private int longitudContenido;
    private String path;

    public ControladorClientes(Socket socket, String path) {
        try {
            impresor = new ImpresorPost();
            unCliente = socket;
            input = new BufferedReader(new InputStreamReader(unCliente.getInputStream()));
            output = new DataOutputStream(unCliente.getOutputStream());
            sesiones = new HashSet<>();
            cabecera = "";
            tipoPeticion = "";
            cookie = "";
            this.path = path;
            longitudContenido = 0;
        } catch (IOException ex) {
            Logger.getLogger(ControladorClientes.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private void analizarPeticion() {
        try {
            String lineaCabecera = input.readLine();
            while (lineaCabecera != null && !lineaCabecera.equals("")) {
                cabecera = cabecera.concat(lineaCabecera + "\r");
                if (lineaCabecera.startsWith(ControladorClientes.PREFIX_GET) || lineaCabecera.startsWith(ControladorClientes.PREFIX_POST)) {
                    tipoPeticion = lineaCabecera;
                }
                if (lineaCabecera.startsWith(ControladorClientes.PREFIX_COOKIE)) {
                    cookie = lineaCabecera;
                    System.out.println("cookie = " + cookie);
                }
                if (lineaCabecera.startsWith("Content-Length: ")) {
                    longitudContenido = Integer.parseInt(lineaCabecera.substring(lineaCabecera.indexOf(" ") + 1));
                    System.out.println("Long contenido = " + longitudContenido);
                }
                lineaCabecera = input.readLine();
            }
            analizarTipoPeticion(tipoPeticion);

            System.out.println(cabecera);
        } catch (IOException ex) {
            //Logger.getLogger(ControladorClientes.class.getName()).log(Level.SEVERE, null, ex);
            System.err.println("[Error] - No se han recibido datos desde el cliente");
        } finally {
            try {
                cerrarConexion();
            } catch (IOException ex) {
                Logger.getLogger(ControladorClientes.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private void analizarTipoPeticion(String tipoPeticion) throws IOException {
        if (tipoPeticion.startsWith(ControladorClientes.PREFIX_GET)) {
            this.obtenerFicheroSolicitado(tipoPeticion);
        } else if (tipoPeticion.startsWith(ControladorClientes.PREFIX_POST)) {
            System.out.println("SE HA PEDIDO UN POST");
            char[] contenidoPost = new char[longitudContenido];
            int read = input.read(contenidoPost);
            StringBuilder strb = new StringBuilder();
            strb.append(contenidoPost, 0, read);
            this.procesarEnvio(strb.toString());
        }
    }

    @Override
    public void run() {
        analizarPeticion();
    }

    private void obtenerFicheroSolicitado(String peticion) throws IOException {
        StringTokenizer stokenizer = new StringTokenizer(peticion);
        //Salto el GET puesto que ya esta comprobado anteriormente.
        stokenizer.nextToken();
        String rutaContenido = stokenizer.nextToken();
        rutaContenido = rutaContenido.substring(1, rutaContenido.length());
        String pathAbsoluto = this.path+rutaContenido;
        File fich = new File(pathAbsoluto);
        //Se comprueba que el fichero existe
        if (!fich.exists()) {
            devolverNotFound();
        } else {
            servirContenidoHttp(pathAbsoluto);
        }
    }

    private void devolverNotFound() {
        String cabeceraNotFound = "HTTP/1.1 404 Not Found\n\n";
        String contenido = cabeceraNotFound
                + "<html><body>"
                + "<h1>Error 404. File not Found</h1>"
                + "</body></html>";
        try {
            output.write(contenido.getBytes());
        } catch (IOException ex) {
            Logger.getLogger(Servidor.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private synchronized void servirContenidoHttp(String rutaContenido) throws IOException {
        Path path = Paths.get(rutaContenido);
        bytesContenido = Files.readAllBytes(path);
        StringBuilder constructorCabeceraOK = new StringBuilder();
        constructorCabeceraOK.append("HTTP/1.1 200 OK");

        if (cookie.isEmpty()) {
            constructorCabeceraOK.append("\r\n").append("Set-Cookie: name=").append(String.valueOf(unCliente.getInetAddress().getHostAddress())).append("\r\n");
            almacenarCookie();
        }
        constructorCabeceraOK.append("\r\n\r\n");
        String cabeceraOK = constructorCabeceraOK.toString();
        byte[] bytesCabecera = cabeceraOK.getBytes();

        byte[] paginaEnviar = new byte[bytesCabecera.length + bytesContenido.length];
        System.arraycopy(bytesCabecera, 0, paginaEnviar, 0, bytesCabecera.length);
        System.arraycopy(bytesContenido, 0, paginaEnviar, 0, bytesContenido.length);
        System.err.println(cabeceraOK);

        output.write(paginaEnviar);
    }

    /**
     * Método que almacena una Cookie
     */
    private synchronized void almacenarCookie() {
        sesiones.add(unCliente.getInetAddress().getHostAddress());
    }

    private void cerrarConexion() throws IOException {
        input.close();
        output.flush();
        output.close();
        unCliente.close();
    }

    private void procesarEnvio(String contenidoEnvio) {
        impresor.imprimirMensaje("[Post] desde: "+ unCliente.getInetAddress().getHostAddress());
        this.impresor.imprimirMensaje(contenidoEnvio);
        String cabeceraOkTrasPost = "HTTP/1.1 200 OK\n\n";
        String contenido = cabeceraOkTrasPost
                + "<html><body>"
                + "<h1>DATOS RECIBIDOS</h1>"
                + "</body></html>";
        try {
            output.write(contenido.getBytes());
        } catch (IOException ex) {
            Logger.getLogger(ControladorClientes.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
